#!/usr/bin/php
<?php
set_time_limit(0);

require_once __DIR__ . DIRECTORY_SEPARATOR . "init.php";

/* 当前时间 */
$datetime = date('Y-m-d H:i:s');

/* 判断redis配置项 */
if (!isset($config->redis) || empty($config->redis)) {
	exit('[' . $datetime . ']' . ' ERROR: 缺少配置项redis或redis下的配置为空！' . PHP_EOL);
}
if (!isset($config->redis->host) || empty($config->redis->host)) {
	exit('[' . $datetime . ']' . ' ERROR: redis缺少配置项host或host为空！' . PHP_EOL);
}
if (!isset($config->redis->port) || empty($config->redis->port)) {
    exit('[' . $datetime . ']' . ' ERROR: redis缺少配置项port或port为空！' . PHP_EOL);
}
/* 判断ssdb配置项 */
if (!isset($config->ssdb) || empty($config->ssdb)) {
    exit('[' . $datetime . ']' . ' ERROR: 缺少配置项ssdb或ssdb下的配置为空！' . PHP_EOL);
}
if (!isset($config->ssdb->host) || empty($config->ssdb->host)) {
    exit('[' . $datetime . ']' . ' ERROR: ssdb缺少配置项host或host为空！' . PHP_EOL);
}
if (!isset($config->ssdb->port) || empty($config->ssdb->port)) {
    exit('[' . $datetime . ']' . ' ERROR: ssdb缺少配置项port或port为空！' . PHP_EOL);
}

/* 判断wlog_host */
if (!isset($config->wlog_host) || empty($config->wlog_host)) {
    exit('[' . $datetime . ']' . ' ERROR: 缺少配置项wlog_host或wlog_host为空！' . PHP_EOL);
}

/* 判断cdn_log_dir */
if (!isset($config->cdn_log_dir) || empty($config->cdn_log_dir)) {
    exit('[' . $datetime . ']' . ' ERROR: 缺少配置项cdn_log_dir或cdn_log_dir为空！' . PHP_EOL);
}

/* 判断log_start_time */
if (!isset($config->log_start_time) || empty($config->log_start_time)) {
    exit('[' . $datetime . ']' . ' ERROR: 缺少配置项log_start_time或log_start_time为空！' . PHP_EOL);
}

/* 判断log_end_time */
if (!isset($config->log_end_time) || empty($config->log_end_time)) {
    exit('[' . $datetime . ']' . ' ERROR: 缺少配置项log_end_time或log_end_time为空！' . PHP_EOL);
}

if (!initRemoteDBConn()) {
    exit('[' . $datetime . ']' . ' ERROR: Initialize remotedb connect error!' . PHP_EOL);
}

/*if (!initSSDBConn()) {
    exit('[' . $datetime . ']' . ' ERROR: Initialize ssdb connect error!' . PHP_EOL);
}*/


$start_time = $config->log_start_time;
$end_time = $config->log_end_time;

if (empty($argv[1])) {
    $date = date('Ymd',strtotime('-1 day'));
} else {
    $date = substr($start_time, 0, 8);
}

/* logpath */
$log_dir = $config->cdn_log_dir . '/';

//遍历该目录下的日志文件
$log_list = getFileList($log_dir, $start_time, $end_time);
if (!$log_list) {
    return false;
}

$versions = [];
foreach ($log_list as $key => $file) {
    if (file_exists($file) == false) {
        exit('[' . $datetime . ']' . ' ERROR: ' . $file . '文件不存在' . PHP_EOL);
    }
    if (is_readable($file) == false) {
        exit('[' . $datetime . ']' . ' ERROR: ' . $file . '文件不可读' . PHP_EOL);
    }
    $fp = fopen($file, "r");
    if($fp == false){
        exit('[' . $datetime . ']' . ' ERROR: ' . $file . '文件打开失败' . PHP_EOL);
     }
    if(filesize($file) == false){
        continue;
    }

    $point = fileIsRunning($file, null);
    //不存在获取为0
    if (is_bool($point) && $point === true) {
        continue;
    }

    if (!$point) {
        fileIsRunning($file, '0');
    } else {
        fseek($fp, $point);
    }

    $data = $items = [];

    while(!@feof($fp)){
        try{
                $line = @fgets($fp);
                if(empty($line)){ continue; }

                /* 以" "分割字符串 */
                $info = explode(' ', $line);
                $created = $info[0];

                /* 是否时间段 */
                /*if ($created < $start_time || $created > $end_time) {
                    continue;
                }*/
                $uri = $info[1];
                //$uri = 'https://yaotv-10022228.file.myqcloud.com/v2/url.html?param=openid%3Dosxe0wGSeF5fBKEQShVu2UExIjLA%26version%3D3c157339057a67c9%26cardid%3D20239%26advid%3D4132%26sharktimeid%3D%26channelmid%3D%26platform%3De%26redirect%3Dhttp%3A%2F%2Fwww.taolixian.com%2Fdemo_index.asp';
                $uri = 'https://yaotv-10022228.file.myqcloud.com/v2/ping.jpg?openid=osxe0wGSeF5fBKEQShVu2UExIjLA&sharktimeid=&channelmid=1782&version=630d2fef2795a29e&cardid=24150&advid=4130&platform=e&callback=jsonp05780862253976677';

                /* 判断card/view */
                if (strpos($uri, '.jpeg') != false || strpos($uri, '.jpg') != false || strpos($uri, '.png') != false) {
                    $array = getSendData('show', $created, $uri, $date);
                /* 判断click/card */
                } else if(strpos($uri, 'url.html') != false) {
                    $array = getSendData('click', $created, $uri, $date);
                } else {
                    continue;
                }

                if (!$array) {
                    continue;
                }

                array_push($items, $array);

                if (isset($array['type'])) {
                    if (isset($versions[$array['version']])) {
                        $versions[$array['version']][$array['type']]++;
                    } else {
                        $versions[$array['version']][$array['type']] = 1;
                    }
                }

                if (count($items) >= 50) {
                    //调用sendPost

                        $data['items'] = $items;
                        $res = sendPost($config->wlog_host, json_encode($data), false);

                        echo '[' . $datetime . ']' . ' MSG: ' . json_encode($res) . PHP_EOL;

                        if (!$res || (isset($res['httpcode']) && $res['httpcode'] != 200)) {
                            file_put_contents($log_dir. 'httperror.log', '[' . $datetime . ']' . ' ' . 'httpcode' . $res['httpcode'] . ' ' . $res['response'] . PHP_EOL, FILE_APPEND);
                            throw new Exception(json_encode($res));
                        }

                        $response = json_decode($res['response'], true);
                        if (isset($response['errcode']) && $response['errcode'] == '0') {
                            $data['items'] = $items = [];
                        }
                }
        } catch (Exception $e) {
            //执行失败
            fileIsRunning($file, ftell($fp));
            exit('[' . $datetime . ']' . ' ERROR: ' . $e->getMessage() . ' on ' . $e->getLine() . ' in ' . $e->getFile());
        }
    }

    //调用sendPost
    if (!$items) {
        continue;
    }
    $data['items'] = $items;
    $res = sendPost($config->wlog_host, json_encode($data), false);

    echo '[' . $datetime . ']' . ' MSG: ' . json_encode($res) . PHP_EOL;

    if (!$res || (isset($res['httpcode']) && $res['httpcode'] != 200)) {
        file_put_contents($log_dir. 'httperror.log', '[' . $datetime . ']' . ' ' . 'httpcode' . $res['httpcode'] . ' ' . $res['response'] . PHP_EOL, FILE_APPEND);
        exit('[' . $datetime . ']' . ' ERROR: ' . json_encode($res));
    }

    $response = json_decode($res['response'], true);
    if (isset($response['errcode']) && $response['errcode'] == '0') {
        $data['items'] = $items = [];
    }

    fileIsRunning($file, '-1');
    //关闭文件
    fclose($fp);
}

foreach ($versions as $vkey => $vv) {
    echo '----------------------------------------------------------------------------------------------' . PHP_EOL;
    echo 'publish:version:' . $vkey . ' ' . json_encode($vv) . PHP_EOL;
}
exit('[' . $datetime . ']' . ' MSG: cdn-log-scanning.php complete!' . PHP_EOL);

/**
 * 遍历目录
 * @param  [string] $dir [文件目录]
 * @param  [string] $start_time [开始时间]
 * @param  [string] $end_time [截至时间]
 * @return [array] [data array]
 */
function getFileList($dir, $start_time, $end_time) {
    static $result = [];
    static $hours = [];
    $stime = strtotime($start_time);
    $etime = strtotime($end_time);
    while ($stime < $etime) {
        $hours[] = substr($start_time, 0, -4);
        $stime = $stime + 3600;
        $start_time = date('YmdHis', $stime);
    }

    if(!is_dir($dir)){
        exit('[' . $datetime . ']' . ' MSG: ' . $dir . '目录不存在' . PHP_EOL);
    }
    if ($dh = opendir($dir)){
        while (($file = readdir($dh)) !== false){
            if((is_dir($dir . $file)) && $file != '.' && $file != '..'){
                        getFileList($dir . $file . '/', $start_time, $end_time);
            }else{
                if($file != '.' && $file != '..'){
                    if(is_file($dir . $file) && substr($file, -4) == 'temp' && in_array(substr($file, 0, 10), $hours)) {
                        $result[] = $dir . $file;
                    }
                }
            }
        }
        closedir($dh);
    }
    return $result;
}

/**
 * 写入日志
 * @param  [string] $type [类型，show|arrive|click]
 * @param  [string] $created [日志生成时间]
 * @param  [string] $uri [uri]
 * @param  [string] $date [日期]
 * @return [bool] [data array]
 */
function getSendData($type, $created, $uri, $date) {
    global $config;

    //static $publishs = [];

    /* 获取参数 */
    $param = getParam($type, $uri);
    if (!$param || !isset($param['version']) || empty($param['version'])) {
        return false;
    }
    /* 判断version中是否存在1000 */
    $prefix = '';
    $version = $param['version'];
    if (strpos($param['version'], '1000') === 0) {
        $prefix = '1000';
        $version = substr($param['version'], 4);
    }
    if (!isset($param['platform']) || empty($param['platform'])) {
        $p[0] = '';
        $p[1] = '1';
    } else {
        $p = getPlatForm($param['platform']);
        if (!$p) {
            return false;
        }
    }

    /*if (!isset($publishs[$version])) {
        $pubInfo = getPublish($version,  $p[0]);
        if (!$pubInfo) {
            return false;
        }  
    }*/

    /*$unfrozen = getBudgetPubAdv($pubInfo['id'], $pubInfo['advertiser_id'], $p[0], $date);
    if (!$unfrozen) {
        return false;
    }*/

    if (!isset($param['sharktimeid']) || empty($param['sharktimeid'])) {
        $param['sharktimeid'] = '0';
    }
    if (!isset($param['openid']) && empty($param['openid'])) {
        return false;
    }
    if (!isset($param['cardid']) && empty($param['cardid'])) {
        return false;
    }
    if (!isset($param['client']) || empty($param['client'])) {
        $param['client'] = '0';
    } else {
        $param['client'] = getClient($param['client']);
    }
    if ($param['sharktimeid'] == '0' && (!isset($param['channelmid']) || empty($param['channelmid']))) {
        return false;
    }

    $uuid = getUUID();
    $microtime = getMicrotime($created);

    /* 调用adcloud-v1.5接口，写入log */
    $param['platform'] = $p[0];
    $param['type'] = $type;
    $param['uuid'] = $uuid;

    $param['version'] = $prefix . $param['version'];

    //测试时version前面加1000
    if (!empty($config->pub_version_prefix) && strpos($param['version'], '1000') !== 0 ) {
        $param['version'] = $config->pub_version_prefix . $param['version'];
    }

    $param['card_cat'] = $p[1];
    
    $param['microtime'] = $microtime;

    return $param;
    /*$result = sendPost($config->wlog_host, $param, false);
    if (!$result) {
        throw new Exception('[' . $datetime . ']' . ' MSG：sendPost return false');
    }
    $result = json_encode($result, true);
    if (!isset($result['errcode']) || $result['errcode'] == '1') {
        throw new Exception('[' . $datetime . ']' . ' MSG：' . $result['msg']);
    }

    return true;*/



    /* 写入到ssdb中，并扣费 */
    /*if (isset($param['tcat_title']) && $param['tcat_title'] == 'finance') {
        $logKey = 'finance:log' . $type . ':' . $uuid;
    } else {
        $logKey = $p[0] . 'log' . $type . ':' . $uuid;
    }

    $logVal = $param['sharktimeid'] . ':' . $param['openid'] . ':' . $prefix . $param['version'] . ':' . $param['card_id'] . ':' . $p[1] . ':' . $microtime;

    if ($param['sharktimeid'] == '0' && $param['channelmid']) {
        $logVal = $logVal . ':' . $param['channelmid'];
    }

    $ok = $config->ssdb->conn->setx($logKey, $logVal, 3600*24*3);
    if ($ok) {
        echo $logKey . PHP_EOL;
        $config->ssdb->conn->incr($p[0] . 'statlog' . $type . ':' . $date);
        $config->ssdb->conn->incr($p[0] . 'statlog' . $type . ':' . $date . ':pub:' . $prefix . $pubInfo['id']);
        $config->ssdb->conn->zset($p[0] . 'statlog' . $type . ':' . $date . ':pub:' . $prefix . $pubInfo['id'] . ':logid', $uuid, time());
        $config->ssdb->conn->hincr($p[0] . 'statlog' . $type . ':sharktimeid:' . $param['sharktimeid'], $prefix . $pubInfo['id']);

        if ($prefix == '' and (($type == 'show' and $pubInfo['billing'] == '1') or ($type == 'click' and $pubInfo['billing'] == '2') or ($type == 'arrive' and $pubInfo['billing'] == '3'))) {
            if ($p[0] == 'ka:' and $p[1] == '1') {
                return true;
            }

            /* 设置投放计划日消费和广告主的总消费 */
            /*if ($pubInfo['product_type'] == '1') {
                $config->remotedb->conn->hincrby($p[0] . 'budget:pub:' . $pubInfo['id'] . ':' . $date, 'consume', 10);
                $config->remotedb->conn->hincrby($p[0] . 'budget:adv:' . $pubInfo['advertiser_id'], 'consume', 10);
            } else {
                $config->remotedb->conn->hincrby($p[0] . 'budget:pub:' . $pubInfo['id'] . ':' . $date, 'consume', $pubInfo['bid']);
                 $config->remotedb->conn->hincrby($p[0] . 'budget:adv:' . $pubInfo['advertiser_id'], 'consume', $pubInfo['bid']);
            }
        }
        return true;
    } else {
        throw new Exception('[' . $datetime . ']' . ' MSG：fail ' . $logKey . '=>' . $logVal);
        //return false;
    }*/
    
}

/**
 * 获取参数
 * @param  [string] $type [类型]
 * @param  [string] $uri [uri]
 * @return [bool|array] [data array]
 */
function getParam($type, $uri) {
    $params = [];
    if (empty($type) || empty($uri)) {
        return false;
    }
    if (strpos($uri, '?') === false/* || strpos($uri, '&') === false*/ || strpos($uri, '=') === false) {
        return false;
    }
    $array = explode('?', $uri);
    if (!isset($array[1]) || empty($array[1])) {
        return false;
    }
    $data = explode('&', $array[1]);
    foreach ($data as $key => $param) {
        $param = explode('=', $param);

        if ($type == 'click') {
            if ($param[0] == 'param') {
                $param[1] = urldecode($param[1]);
                $datac = explode('&', $param[1]);
                foreach ($datac as $keyc => $paramc) {
                    $paramc = explode('=', $paramc);
                    $params[$paramc[0]] = $paramc[1];
                }
            }
        } else {
            if ($param[0] == 'version' && strpos($param[1], ':') != false) {
                $version = explode(':', $param[1]);
                $params[$param[0]] = $version[0];
                $params['cardid'] = $version[1];
            } else {
                $params[$param[0]] = $param[1];
            }
        }
    }

    return $params;
}

/**
 * 判断platform
 * @param  [string] $platform [平台]
 * @return [array] [data array]
 */
function getPlatForm($platform) {
    if (!$platform) {
        return false;
    }

    $default = ['e', 'e:1', 'e:2', 'e:3', 'dmp', 'ka:e', 'ka:dmp', 'ka:1', 'ka:2'];
    if (!in_array($platform, $default)) {
        return false;
    }
    $p = explode(':', $platform);
    if ( ($p[0] == 'e' && !isset($p[1])) || ($p[0] == 'ka' && isset($p[1]) && $p[1] == 'e') ) {
        $p[1] = '1';
    } else if($p[0] == 'dmp' || ($p[0] == 'ka' && isset($p[1]) && $p[1] == 'dmp') ) {
        $p[1] = '2';
    }

    $p[0] = $p[0] == 'e' ? '' : $p[0] .= ':';

    return $p;
}

/**
 * 判断client
 * @param  [string] $client
 * @return [string] [data array]
 */
function getClient($client) {
    if (empty($client)) {
        $client = '0';
    } else if ($client == 'yaotv') {
        $client = '1';
    } else if ($client == 'app') {
        $client = '2';
    } else if ($client == 'alipay') {
        $client = '3';
    } else {
        $client = '0';
    }
    return $client;
}
/**
 * 获取投放计划
 * @param  [string] $version [投放计划version]
 * @return [array] [data array]
 */
function getPublish($version, $platform) {
    global $config;
    $pubKey = $platform . 'publishs:version:' . $version;
    $pubParam = array('id', 'advertiser_id', 'product_type', 'billing', 'bid');
    $pubInfo =  $config->remotedb->conn->hMGet($pubKey,$pubParam);
    if (!$pubInfo['id'] || !$pubInfo['advertiser_id'] || !$pubInfo['product_type'] || !$pubInfo['billing']  || !$pubInfo['bid']) {
        return false;
    }
    return $pubInfo;
}

/**
 * 获取预算及消费
 * @param  [int] $pubId [投放计划ID]
 * @param  [int] $advId [广告主ID]
 * @param  [string] $platform [平台]
 * @param  [string] $date [日期，20161212]
 * @return [bool] [data array]
 */
function getBudgetPubAdv($pubId, $advId, $platform, $date) {
    global $config;

    $pubKey = $platform . 'budget:pub:' . $pubId . ':' . $date;
    $pubData = $config->remotedb->conn->hMget($pubKey, ['ceiling', 'consume']);
    if (!$pubData || empty($pubData['ceiling'])) {
        return false;
    }
    if ($pubData['ceiling'] - $pubData['consume'] <= 0) {
        return false;
    }

    $advKey = $platform . 'budget:adv:' . $advId;
    $advData = $config->remotedb->conn->hMget($advKey, ['amount', 'consume']);
    if (!$advData || empty($advData['amount'])) {
        return false;
    }
    if ($advData['amount'] - $advData['consume'] <= 0) {
        return false;
    }
    return true;
}

/**
 * 获取microtime
 * @param  [string] $created [日志生成时间]
 * @return [string] [data array]
 */
function getMicrotime($created) {
    $time = $created ? $created : date('YmdHis');
    //获取microtime
    list($usec, $sec) = explode(' ', microtime());
    $microsec = substr((float)$usec, 2, 3);
    $microtime = $time . $microsec;
    if (strlen($microtime) < 17) {
        $microtime .= str_repeat('0', 17-strlen($microtime));
    }

    return $microtime;
}

/**
 * 获取uuid
 * @param  [string]
 * @return [string] [data array]
 */
function getUUID() {
    return substr(md5(uniqid(mt_rand(), true)), 0, 16);
}

/**
 * CURL
 * @param  [string] $FullHttpUrl
 * @param  [array] $Req
 * @param  [bool] $isHttps
 * @return [string] [data array]
 */
function sendPost($FullHttpUrl, $Req, $isHttps)
{
        $ch = curl_init();
        curl_setopt($ch, CURLOPT_POST, 1);
        curl_setopt($ch, CURLOPT_POSTFIELDS, $Req);

        curl_setopt($ch, CURLOPT_URL, $FullHttpUrl);
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
        if ($isHttps === true) {
                curl_setopt($ch, CURLOPT_SSL_VERIFYPEER,  false);
                curl_setopt($ch, CURLOPT_SSL_VERIFYHOST,  false);
        }

        curl_setopt($ch, CURLOPT_TIMEOUT, 5);
        curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 5);
        curl_setopt($ch, CURLOPT_HEADER, 0);

        $httpbady = curl_exec($ch);

        $httpcode = curl_getinfo($ch, CURLINFO_HTTP_CODE);

        $result = array(
            "httpcode" => $httpcode,
            "response" => $httpbady
        );

        if(!$httpbady || curl_errno($ch)){ 
            return false;
        }

        curl_close($ch);

        return $result;
}

/**
 * 判断文件是否正在执行，用于启动多进程判断
 * @param  [string] $file [文件绝对地址]
 * @param  [string] $point [文件指针，不存在则判断文件是否存在，运行时初始化指针为0，失败时为该时的文件指针]
 * @return [array] [data array]
 */
function fileIsRunning($file, $point) {
    global $config;

    if (!$file) {
        return false;
    }
    $file = explode('/', $file);

    $redisKey = 'cdn:logListRunning';
    $redisField = end($file);

    //判断文件是否已经运行
    if ($point == null) {
        $res = $config->remotedb->conn->hget($redisKey, $redisField);
        //bool(false)
        if ($res === false) {
            return false;
        } else if ($res === '0' || $res == '-1') {
            return true;
        } else {
            return $res;
        }
    //设置文件指针，初始化为0
    } else {
        $res = $config->remotedb->conn->hset($redisKey, $redisField, $point);
        //int(1)
        if ($res) {
            return true;
        } else {
            return false;
        }
    }
}

?>